package com.cinsea.workflow.service;

import com.cinsea.common.BaseService;
import com.cinsea.common.Env;
import com.cinsea.common.JdbcDao;
import com.cinsea.form.model.Form;
import com.cinsea.form.model.Formfield;
import com.cinsea.form.service.FormService;
import com.cinsea.form.service.FormfieldService;
import com.cinsea.hrm.model.Human;
import com.cinsea.hrm.service.HumanService;
import com.cinsea.msg.Message;
import com.cinsea.msg.MessageProducer;
import com.cinsea.util.DateUtil;
import com.cinsea.util.NumberUtil;
import com.cinsea.util.StringUtil;
import com.cinsea.workflow.model.Wfnode;
import com.cinsea.workflow.model.Wfprocess;
import com.cinsea.workflow.model.Wftimeout;

import java.util.*;

/**
 * 流程超时逻辑
 * User: xf
 * Date: 12-9-27
 * Time: 下午12:25
 */
public class WftimeoutmakerService extends BaseService implements WftimeoutMaker {
    private FormfieldService formfieldService;
    private FormService formService;
    private JdbcDao jdbcDao;
    private WftimeoutService wftimeoutService;
    private WfworkitemService wfworkitemService;
    private WfprocessService wfprocessService;
    private MessageProducer messageProducer;
    private HumanService humanService;

    public WftimeoutmakerService() {
        formfieldService = Env.getBean("formfieldService");
        formService = Env.getBean("formService");
        jdbcDao = Env.getBean("jdbcDao");
        wftimeoutService = Env.getBean("wftimeoutService");
        wfworkitemService = Env.getBean("wfworkitemService");
        wfprocessService = Env.getBean("wfprocessService");
        messageProducer = Env.getBean("messageProducer");
        humanService = Env.getBean("humanService");
    }

    /**
     * @param processid
     * @param _wfnode
     * @param submitted 计时起点 true提交后 false接收后
     */
    public void makeTimeout(String processid, Wfnode _wfnode, boolean submitted) {
        Integer istimeout = _wfnode.getTimeoutenable();
        Integer timeoutstart = _wfnode.getTimestartpoint();
        Integer timeouttype = _wfnode.getTimetype();
        if (istimeout == null || timeoutstart == null || timeouttype == null)
            return;

        if (istimeout.intValue() != 1)
            return;

        if (!((timeoutstart.intValue() == 1 && !submitted) || (timeoutstart.intValue() != 1 && submitted)))
            return;

        String timeoutvalue = "";

        if (timeouttype.intValue() == 0) {
            timeoutvalue = StringUtil.null2String(_wfnode.getTimevalue());
        } else if (timeouttype.intValue() == 1) {
            String timeoutfieldid = StringUtil.null2String(_wfnode.getTimefieldid());

            Formfield _formfield = formfieldService.getFormfieldById(timeoutfieldid);
            String _fieldname = StringUtil.null2String(_formfield.getFieldname());

            String _formid = StringUtil.null2String(_formfield.getFormid());
            Form _form = formService.getFormById(_formid);

            String _tablename = StringUtil.null2String(_form.getTablename());
            if (StringUtil.isEmpty(_tablename) || StringUtil.isEmpty(_fieldname))
                return;

            String sql = "select " + _fieldname + " from " + _tablename + " where processid = '" + processid + "'";
            List idlist = jdbcDao.queryForList(sql);
            if (idlist != null) {
                for (int j = 0; j < idlist.size(); j++) {
                    Map map = (Map) idlist.get(j);
                    timeoutvalue = StringUtil.null2String(map.get(_fieldname));
                    break;
                }
            }
        }
        Calendar today1 = null;
        String reminddate = "";
        String remindtime = "00:00:00";
        if (timeoutstart.intValue() == 2) {
            reminddate = timeoutvalue;
        } else {
            Integer timeunit = _wfnode.getTimeunit();
            if (timeunit != null) {
                int itimeunit = timeunit.intValue();
                Calendar today = new GregorianCalendar();
                Date trialTime = new Date();
                today.setTime(trialTime);
                int offtime = NumberUtil.string2Int(timeoutvalue, 0);
                if (offtime != 0) {
                    if (itimeunit == 1) {//小时
                        if (offtime < 2) return;
                        int offtime1 = offtime / 2;
                        today1 = new GregorianCalendar();
                        today1.setTime(trialTime);
                        today.add(Calendar.HOUR, offtime);
                        today1.add(Calendar.HOUR, offtime1);

                    } else if (itimeunit == 2) {//天

                        today.add(Calendar.DATE, offtime);

                    } else if (itimeunit == 3) {//周

                        today.add(Calendar.WEEK_OF_YEAR, offtime);

                    } else if (itimeunit == 4) {//月

                        today.add(Calendar.MONTH, offtime);

                    } else if (itimeunit == 5) {//季度
                        today.add(Calendar.MONTH, offtime * 3);
                    }

                    reminddate = NumberUtil.add0(today.get(Calendar.YEAR), 4) + "-" + NumberUtil.add0(today.get(Calendar.MONTH) + 1, 2) + "-" + NumberUtil.add0(today.get(Calendar.DATE), 2);

                    remindtime = NumberUtil.add0(today.get(Calendar.HOUR_OF_DAY), 2) + ":" + NumberUtil.add0(today.get(Calendar.MINUTE), 2) + ":" + NumberUtil.add0(today.get(Calendar.SECOND), 2);
                }
            }
        }

        if (reminddate.equals("") || reminddate.length() > 10)
            return;

        Integer timeoutopt = _wfnode.getTimeoutaction();
        String timeoutnodeid = StringUtil.null2String(_wfnode.getRedirectnodeid());
        if (today1 != null && timeoutopt != null && timeoutopt == 0) {//超时时间过半时邮件提醒（仅用于以小时为单位的超时提醒设置）
            String reminddate1 = NumberUtil.add0(today1.get(Calendar.YEAR), 4) + "-" + NumberUtil.add0(today1.get(Calendar.MONTH) + 1, 2) + "-" + NumberUtil.add0(today1.get(Calendar.DATE), 2);
            reminddate1 = getWorkday(reminddate1);
            Wftimeout wftimeout = new Wftimeout();
            wftimeout.setProcessid(processid);
            wftimeout.setNodeid(_wfnode.getId());
            wftimeout.setTimeoutdate(reminddate1);
            wftimeout.setTimeouttime(remindtime);
            wftimeout.setTimeoutaction(timeoutopt);
            wftimeout.setRedirectnodeid("half");
            wftimeout.setWorkflowid(_wfnode.getWorkflowid());
            wftimeoutService.save(wftimeout);

        }
        //超时短信提醒
        reminddate = getWorkday(reminddate);
        Wftimeout wftimeout = new Wftimeout();
        wftimeout.setProcessid(processid);
        wftimeout.setNodeid(_wfnode.getId());
        wftimeout.setTimeoutdate(reminddate);
        wftimeout.setTimeouttime(remindtime);
        wftimeout.setTimeoutaction(timeoutopt);
        wftimeout.setRedirectnodeid(timeoutnodeid);
        wftimeout.setWorkflowid(_wfnode.getWorkflowid());
        wftimeoutService.save(wftimeout);
    }

    public void checkTimeout() {
        if (Env.getApplicationContext() == null)
            return;
        String hql = "from Wftimeout";
        List<Wftimeout> list = wftimeoutService.find(hql);
        for (Wftimeout wftimeout : list) {
            if (checkNoderemind(wftimeout)) {
                String processid = StringUtil.null2String(wftimeout.getProcessid());
                String nodeid = StringUtil.null2String(wftimeout.getNodeid());
                String requesthost = StringUtil.null2String(Env.getServername());
                String contextpath = StringUtil.null2String(Env.getContextpath());
                Integer exeaction = wftimeout.getTimeoutaction();
                String redirectnodeid = StringUtil.null2String(wftimeout.getRedirectnodeid());
                wftimeoutService.delete(wftimeout);

                if (exeaction == null)
                    continue;

                Map parameters = new HashMap();
                parameters.put("processid", processid);
                parameters.put("nodeid", nodeid);
                if (exeaction.intValue() == 0) {
                    boolean ishalf = false;
                    if (redirectnodeid.equals("half")) ishalf = true;
                    if (remindWorkflow(parameters, ishalf))
                        logger.info("流程节点超时被提醒！" + processid + ":" + nodeid);

                } else if (exeaction.intValue() == 1) {
                    if (wftimeoutService.flowWorkflow(parameters))
                        logger.info("流程节点超时自动执行！" + processid + ":" + nodeid);
                } else if (exeaction.intValue() == 2) {

                    parameters.put("redirectnodeid", redirectnodeid);
                    if (wftimeoutService.flowWorkflow(parameters))
                        logger.info("流程节点超时被重定向！" + processid + ":" + nodeid + ":" + redirectnodeid);
                }
            }
        }
    }

    private boolean checkNoderemind(Wftimeout wftimeout) {
        boolean bResult = false;

        String triggerdate = StringUtil.null2String(wftimeout.getTimeoutdate());
        String triggertime = StringUtil.null2String(wftimeout.getTimeouttime());

        Calendar calendar = new GregorianCalendar();
        Date trialTime = new Date();
        calendar.setTime(trialTime);

        int month = calendar.get(Calendar.MONTH) + 1;
        int day = calendar.get(Calendar.DATE);

        String date1 = NumberUtil.add0(month, 2) + "-" + NumberUtil.add0(day, 2);
        if (triggerdate.length() != 10)
            return bResult;
        String date2 = triggerdate.substring(5);
        if (!date1.equals(date2))
            return bResult;


        if (triggertime.length() < 5)
            return bResult;

        Date trialTime1 = new Date();
        trialTime1.setHours(NumberUtil.string2Int(triggertime.substring(0, 2)));
        trialTime1.setMinutes(NumberUtil.string2Int(triggertime.substring(3, 5)));
        if (trialTime.getTime() - trialTime1.getTime() >= 0)
            bResult = true;

        return bResult;
    }

    public boolean remindWorkflow(Map parameters, boolean ishalf) {
        boolean bRet = true;

        String receivers = "";
        String processid = StringUtil.null2String(parameters.get("processid"));
        String nodeid = StringUtil.null2String(parameters.get("nodeid"));
        String requesthost = StringUtil.null2String(Env.getServername());
        String contextpath = StringUtil.null2String(Env.getContextpath());

        if (StringUtil.isEmpty(processid) || StringUtil.isEmpty(nodeid))
            return false;
        String hql = "select distinct wo.userid from Wfworkitem wo where wo.opttype>1 and wo.submitted=0 and wo.processid = '" + processid + "' and wo.nodeid = '" + nodeid + "'";//非知会未操作人

        List li = wfworkitemService.find(hql);
        for (int i = 0; i < li.size(); i++) {
            String receiver = StringUtil.null2String(li.get(i));
            if (!StringUtil.isEmpty(receiver)) {
                if (ishalf) {//todo
                    Human human = humanService.getFree(receiver);
                    if (human != null && human.getEmail() != null && NumberUtil.getIntegerValue(human.getSeclevel()) <= 80)//安全級別小于等于80邮件提醒
                        receivers += "," + receiver;
                } else
                    receivers += "," + receiver;
            }

        }
        Wfprocess wfprocess = this.wfprocessService.getWfprocess(processid);
        String msg = "流程超时提醒:“ " + StringUtil.null2String(wfprocess.getTitle()) + " ”,请尽快处理!";
        if (receivers.indexOf(",") == 0) receivers = receivers.substring(1);
        if (StringUtil.isEmpty(receivers)) return false;
        if (ishalf) {
            String msg1 = requesthost + contextpath + "/workflow/wfprocess.jsp?processid=" + processid;
            msg1 = requesthost + contextpath + "/workflow/wfprocess.jsp?processid=" + processid;
            msg = "<a href=\"" + msg1 + "\">" + msg + "</a>";
            Message msgobj = new Message(Message.MESSAGE_TYPE_EMAIL, "11111111111111111111111111111111", receivers, msg);
            msgobj.setMsgtitle("<<" + StringUtil.null2String(wfprocess.getTitle()) + ">> is timeout ");
            messageProducer.send(msgobj);


        } else {
            Message msgobj = new Message(Message.MESSAGE_TYPE_SMS, "11111111111111111111111111111111", receivers, msg);
            msgobj.setMsgtitle("<<" + StringUtil.null2String(wfprocess.getTitle()) + ">> is timeout ");
            messageProducer.send(msgobj);
        }

        return bRet;
    }

    private String getWorkday(String datestr) {
        while (!isWorkday(datestr)) {
            datestr = DateUtil.dayMove(datestr, 1);
        }
        return datestr;
    }

    private boolean isWorkday(String datestr) {
        //是否周六周日
        return DateUtil.isWorkDay(datestr);
    }
}
